<?xml version="1.0"?>
<OnTheFlyInstruction xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <InstanceId>SP_RestoreSearchProperties</InstanceId>
  <CustomAppConfig />
  <Tags>
    <string>SharePoint</string>
  </Tags>
  <AdditionalAssemblies>
    <string>C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.Office.Server.dll</string>
  </AdditionalAssemblies>
  <Code><![CDATA[// Create/Updates Managed properties from xml file
// SP_RestoreSearchProperties.inst
// v 0.0.1 - 2013-07-15 - rev 0 - mmachado
// v 0.0.2 				- GetValue did not parse ManagedMetadata field
//						- Added text variant 31 for crawled properties mapping
// v 0.0.3 - 2013-08-07 - removed call to depreacted API - mmachado
//							SearchContext.GetContext
using System;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Xml;
using Microsoft.Office.Server.Search.Administration;
using Microsoft.SharePoint;
using xSolon.Instructions;

public class AddSPSearchProps : AbstractInstruction
{

    /// <summary>
    /// Entry point.
    /// </summary>
    public override void Run()
    {
        Run1();
    }

    public void Run1()
    {
        InternalRun("http://localhost", @"c:\hmsearch.txt");
    }

    public void Run(object url, object path1)
    {
        InternalRun(url.ToString(), path1.ToString());
    }

    void InternalRun(string url, string tablePath)
    {
        var ds = new DataSet();

        ds.ReadXml(tablePath.ToString());

        var dt = ds.Tables[0];

        Log(dt.Rows.Count.ToString());

        using (SPSite site = new SPSite(url.ToString()))
        {
            EnsureSearchProperties(site, dt);
        }
    }

    public void Log(string msg)
    {
        NotifyInformation(msg);
        Trace.WriteLine(msg);
        Console.WriteLine(msg);
    }

    internal void EnsureSearchProperties(SPSite site, DataTable props)
    {
        #region Sample

        //        <ID>&lt;string&gt;NiddkAcronym&lt;/string&gt;</ID>
        //<PID>&lt;int&gt;435&lt;/int&gt;</PID>
        //<Name>&lt;string&gt;NiddkAcronym&lt;/string&gt;</Name>
        //<SplitStringCharacters>NULL</SplitStringCharacters>
        //<SplitStringOnSpace>&lt;boolean&gt;false&lt;/boolean&gt;</SplitStringOnSpace>
        //<Description>&lt;string&gt;NiddkAcronym&lt;/string&gt;</Description>
        //<ManagedType>&lt;ManagedDataType&gt;Text&lt;/ManagedDataType&gt;</ManagedType>
        //<FullTextQueriable>&lt;boolean&gt;true&lt;/boolean&gt;</FullTextQueriable>
        //<Retrievable>&lt;boolean&gt;true&lt;/boolean&gt;</Retrievable>
        //<UseAAMMapping>&lt;boolean&gt;false&lt;/boolean&gt;</UseAAMMapping>
        //<MappingDisallowed>&lt;boolean&gt;false&lt;/boolean&gt;</MappingDisallowed>
        //<DeleteDisallowed>&lt;boolean&gt;false&lt;/boolean&gt;</DeleteDisallowed>
        //<QueryIndependentRankCustomizationDisallowed>&lt;boolean&gt;true&lt;/boolean&gt;</QueryIndependentRankCustomizationDisallowed>
        //<EnabledForScoping>&lt;boolean&gt;false&lt;/boolean&gt;</EnabledForScoping>
        //<NameNormalized>&lt;boolean&gt;false&lt;/boolean&gt;</NameNormalized>
        //<RespectPriority>&lt;boolean&gt;false&lt;/boolean&gt;</RespectPriority>
        //<RemoveDuplicates>&lt;boolean&gt;true&lt;/boolean&gt;</RemoveDuplicates>
        //<HasMultipleValues>&lt;boolean&gt;false&lt;/boolean&gt;</HasMultipleValues>
        //<OverrideValueOfHasMultipleValues>&lt;boolean&gt;false&lt;/boolean&gt;</OverrideValueOfHasMultipleValues>
        //<IsInDocProps>&lt;boolean&gt;true&lt;/boolean&gt;</IsInDocProps>
        //<IncludeInMd5>&lt;boolean&gt;false&lt;/boolean&gt;</IncludeInMd5>
        //<NoWordBreaker>&lt;boolean&gt;false&lt;/boolean&gt;</NoWordBreaker>
        //<UserFlags>&lt;short&gt;0&lt;/short&gt;</UserFlags>
        //<Weight>&lt;float&gt;0&lt;/float&gt;</Weight>
        //<LengthNormalization>&lt;float&gt;0&lt;/float&gt;</LengthNormalization>
        //<EnabledForQueryIndependentRank>&lt;boolean&gt;false&lt;/boolean&gt;</EnabledForQueryIndependentRank>
        //<DefaultForQueryIndependentRank>&lt;unsignedInt&gt;0&lt;/unsignedInt&gt;</DefaultForQueryIndependentRank>
        //<IsInFixedColumnOptimizedResults>&lt;boolean&gt;false&lt;/boolean&gt;</IsInFixedColumnOptimizedResults>
        //<RetrievableForResultsOnly>&lt;boolean&gt;false&lt;/boolean&gt;</RetrievableForResultsOnly>
        //<PutInPropertyBlob>&lt;boolean&gt;false&lt;/boolean&gt;</PutInPropertyBlob>
        //<QueryPropertyBlob>&lt;boolean&gt;false&lt;/boolean&gt;</QueryPropertyBlob>
        //<UsePronunciationString>&lt;boolean&gt;false&lt;/boolean&gt;</UsePronunciationString>
        //<MaxCharactersInPropertyStoreIndex>&lt;int&gt;0&lt;/int&gt;</MaxCharactersInPropertyStoreIndex>
        //<MaxCharactersInPropertyStoreNonIndex>&lt;int&gt;4000&lt;/int&gt;</MaxCharactersInPropertyStoreNonIndex>
        //<EqualityMatchOnly>&lt;boolean&gt;true&lt;/boolean&gt;</EqualityMatchOnly>
        //<MaxCharactersInPropertyStoreForRetrieval>&lt;int&gt;65536&lt;/int&gt;</MaxCharactersInPropertyStoreForRetrieval>
        //<DecimalPlaces>&lt;int&gt;4&lt;/int&gt;</DecimalPlaces>
        //<IsBacked>&lt;boolean&gt;true&lt;/boolean&gt;</IsBacked>
        //<CrawledProps>,ows_Acronym</CrawledProps> 

        #endregion

        SPServiceContext serviceContext = SPServiceContext.GetContext(site);

        // Get the SearchApplicationProxy object from service context object
        SearchServiceApplicationProxy searchApplicationProxy = serviceContext.GetDefaultProxy(typeof(SearchServiceApplicationProxy)) as SearchServiceApplicationProxy;

        // Get the identifier for the search service application from the proxy class retrieved above.
        Guid applicationId = searchApplicationProxy.GetSearchServiceApplicationInfo().SearchServiceApplicationId;

        // Lastly, retreieve the SearchServiceApplication object for the current site.
        SearchServiceApplication searchApplication = SearchService.Service.SearchApplications.GetValue<SearchServiceApplication>(applicationId);
        
        //--
        // Deprecated API
        //Schema sspSchema = new Schema(SearchContext.GetContext(site));
        
        Schema sspSchema = new Schema(searchApplication);
        
        ManagedPropertyCollection properties = sspSchema.AllManagedProperties;

        var type = typeof(ManagedProperty);

        foreach (DataRow prop in props.Rows)
        {
            var id = GetValue(prop, "ID").ToString();

            ManagedProperty sProp = null;

            if (!properties.Contains(id))
            {
                Log(string.Format("Creating search property: {0}", id));

                sProp = properties.Create(
                    id,
                    (ManagedDataType)GetValue(prop, "ManagedType"));
            }
            else
            {
                sProp = properties[id];
            }

            if (sProp != null)
            {

                #region Crawled Properties

                var crawledProps = prop["CrawledProps"].ToString()
                                                       .Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                var mappings = new MappingCollection();

                crawledProps.ToList().ForEach(i =>
                {

                    var spCrawProps = sspSchema.QueryCrawledProperties(i, 4, Guid.NewGuid(), string.Empty, true).OfType<CrawledProperty>().ToList();

                    if (spCrawProps.Count == 0)
                    {
                        Log(string.Format("Error: could not find crawled property {0}", i));
                    }
                    else
                    {
                        spCrawProps.ForEach(x =>
                        {
                            try
                            {
                                bool add = false;
								NotifyInformation("{0} {1}", sProp.ManagedType,x.VariantType);
                                if (sProp.ManagedType == ManagedDataType.Text && (x.VariantType == 32 || x.VariantType == 31))
                                    add = true;
                                if (sProp.ManagedType == ManagedDataType.DateTime && x.VariantType == 64)
                                    add = true;
                                if (sProp.ManagedType == ManagedDataType.Integer && x.VariantType == 20)
                                    add = true;
                                if (sProp.ManagedType == ManagedDataType.YesNo && x.VariantType == 11)
                                    add = true;

                                if (add)
                                {
                                    Log(string.Format("Adding crawled property {0} variant: {1}", x.Name, x.VariantType));
                                    mappings.Add(new Mapping(x.Propset, x.Name, x.VariantType, sProp.PID));
                                }
                            }
                            catch (Exception ex)
                            {
                                Log(ex.ToString());
                            }
                        });

                    }
                });

                sProp.DeleteAllMappings();

                sProp.SetMappings(mappings);

                #endregion

                #region Fields

                var field = type.GetFields(BindingFlags.Public | BindingFlags.Instance).ToList();

                field.ForEach(i =>
                {
                    try
                    {
                        var value = GetValue(prop, i.Name);
                        Log(string.Format("Setting field: {0}: {1}", i.Name, value));
                        i.SetValue(sProp, value);
                    }
                    catch (Exception ex)
                    {
                        Log(ex.ToString());
                    }
                });

                #endregion

                #region Properties

                var refProps = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList();

                refProps.ForEach(i =>
                {
                    try
                    {
                        if (i.CanWrite && i.Name != "DefaultForQueryIndependentRank" && i.Name != "EnabledForQueryIndependentRank")
                        {
                            var value = GetValue(prop, i.Name);
                            Log(string.Format("Setting property: {0}: {1}", i.Name, value));
                            i.SetValue(sProp, value, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log(ex.ToString());
                    }
                });

                #endregion

                sProp.Update();
            }
        }
    }

    public object GetValue(DataRow row, string columnName)
    {
        var rawValue = row[columnName].ToString();

        //Log(rawValue);
        if (rawValue == "NULL")
        {
            return null;
        }
        if (rawValue == "")
        {
            return "";
        }

        if (rawValue.StartsWith("<"))
        {
            var doc = new XmlDocument();
            doc.LoadXml(rawValue);

            var name = doc.DocumentElement.LocalName.ToLower();

            if (name == "string")
            {
                return doc.InnerText;
            }
            else if (name == "int")
            {
                return int.Parse(doc.InnerText);
            }
            else if (name == "boolean")
            {
                return Boolean.Parse(doc.InnerText);
            }
            else if (name == "manageddatatype")
            {
                return Enum.Parse(typeof(ManagedDataType), doc.InnerText);
            }
            else if (name == "short")
            {
                return short.Parse(doc.InnerText);
            }
            else if (name == "float")
            {
                return float.Parse(doc.InnerText);
            }
            else if (name == "unsignedInt")
            {
                return uint.Parse(doc.InnerText);
            }
        }

        throw new Exception(string.Format("Couldn't handle value {0}", columnName));
    }
}
]]></Code>
</OnTheFlyInstruction>